﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App.Modelo.Interfaces;
using App.Persistencia;
using App.SolInf.Modelo;
using NHibernate;

namespace App.SolInf.Controlador
{
    public class ControladoraPresupuestos : IControladora
    {
        public ISessionActual Session { get; set; }

        public IRepositorio Repositorio { get; set; }
        
        private TimeSpan VENCIMIENTO = new TimeSpan(1,0,0,0);

        public void Alta(Presupuesto presupuesto)
        {
            if (presupuesto.Cliente == null)
                throw new Exception("El cliente no puede ser nulo");

            if (presupuesto.Total <= 0 )
                throw new Exception("El total del presupuesto no puede ser cero");

            presupuesto.FechaAlta = DateTime.Now;
            presupuesto.FechaVencimiento = CalcularVencimiento(presupuesto);
            

            Repositorio.SaveObject(presupuesto);
        }

        public DateTime CalcularVencimiento(Presupuesto presupuesto)
        {
            return DateTime.Now.Add(VENCIMIENTO);
        }

        public IList<Presupuesto> Buscar()
        {
            return Repositorio.GetAll<Presupuesto>();
        }

        public void Modificar(Presupuesto presupuesto)
        {
            if (presupuesto.Cliente == null)
                throw new Exception("El cliente no puede ser nulo");

            if (Math.Abs(presupuesto.Total - 0) < Double.Epsilon)
                throw new Exception("El total del presupuesto no puede ser cero");

            presupuesto.FechaAlta = DateTime.Now;
            presupuesto.FechaVencimiento = DateTime.Now.Add(VENCIMIENTO);

            Repositorio.UpdateObject(presupuesto);
            Repositorio.FlushSession();
        }

        public void Baja(Presupuesto item)
        {
            Repositorio.DeleteObject(item);
            Repositorio.FlushSession();
        }

        public void AprobarPresupuesto(Presupuesto presupuesto)
        {
            try
            {
                Repositorio.BeginTransaccion();
                Repositorio.UpdateObject(presupuesto);  

                if (!presupuesto.EstaVigente)
                    throw new PresupuestoVencidoException { Presupuesto = presupuesto };


                var sinStock = ComprobarStockProductos(presupuesto);

                if (sinStock.Count > 0)
                    throw new StockInsuficienteException { Productos = sinStock };

                // registro el movimiento de stock
                var movimiento   = new Movimiento
                                     {
                                         Fecha = DateTime.Now,
                                         Detalle = new Venta()
                                                       {
                                                           Cliente = presupuesto.Cliente,
                                                           Documentacion = new Documentacion()
                                                                               {
                                                                                   Fecha = DateTime.Now,
                                                                                   Tipo = TipoDocumentacion.NotaDeVenta,
                                                                                   Numero = presupuesto.Id.ToString()
                                                                               },
                                                       }
                                     };


                if (Session != null)
                    movimiento.Empleado = Session.UsuarioActual;

                movimiento.Lineas = (from l in presupuesto.LineasPresupuesto
                                     select new LineaMovimiento(l.Producto, -1 * l.Cantidad)).ToList();

                Repositorio.SaveObject(movimiento);
                if (Session != null)
                    presupuesto.Vendedor = Session.UsuarioActual;

                presupuesto.Estado = EstadoPresupuesto.Aprobado;

                Repositorio.UpdateObject(presupuesto);
                Repositorio.CommitTransaction();
                Repositorio.FlushSession();
            }
            catch (Exception)
            {
                Repositorio.RoolbackTransaction();
                throw;
            }
        }

        private static List<Producto> ComprobarStockProductos(Presupuesto presupuesto)
        {
            return (from linea in presupuesto.LineasPresupuesto
                    where linea.Cantidad > linea.Producto.Stock
                    select linea.Producto).ToList();
        }

        public int GetNroPesupuesto()
        {
            return Repositorio.GetAll<Presupuesto>().Count + 1;
        }

        public ICriteria Consultar()
        {
            return ((Repositorio) Repositorio).CreateCriteria<Presupuesto>()
                .CreateAlias("Cliente", "Cliente");
        }
    }
}
